package com.qen.encrypt.http;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 重新包装HttpServletRequest类
 */
public class DecryptHttpServletRequestWrapper extends HttpServletRequestWrapper implements CustomServletRequest {
    private byte[] body;
    private String bodyString;
    private final Map<String, String[]> params = new HashMap<>();

    public DecryptHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        Enumeration<String> enumeration = request.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String paramName = enumeration.nextElement();
            this.params.put(paramName, request.getParameterValues(paramName));
        }
        StringBuilder builder = new StringBuilder();
        ServletInputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            inputStream = request.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            char[] charBuffer = new char[128];
            int bytesRead;
            while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
                builder.append(charBuffer, 0, bytesRead);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.bodyString = builder.toString();
        this.body = builder.toString().getBytes(StandardCharsets.UTF_8);
    }

    public void addParameter(String key, String[] value) {
        this.params.put(key, value);
    }

    @Override
    public String getParameter(String name) {
        String[] values = params.get(name);
        if (values != null && values.length > 0) {
            return values[0];
        }
        return super.getParameter(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        return Collections.unmodifiableMap(params);
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(params.keySet());
    }

    @Override
    public String[] getParameterValues(String name) {
        return params.get(name);
    }

    @Override
    public Object getAttribute(String name) {
        // 此处是为了解决 @PathVariable 参数加密的问题 ，但是会影响请求链接，所以删除吧
//        if (Objects.equals(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, name)) {
//            Map<String, String> map = (Map) super.getAttribute(name);
//            try {
//                Map<String, String> par = new HashMap<>();
//                for (Map.Entry<String, String> entry : map.entrySet()) {
//                    if (encryptSet.contains(entry.getKey())) {
//                        par.put(entry.getKey(), AESUtils.decrypt(entry.getValue(), key));
//                    } else {
//                        par.put(entry.getKey(), entry.getValue());
//                    }
//                }
//                return par;
//            } catch (Exception e) {
//                e.printStackTrace();
//                return super.getAttribute(name);
//            }
//        }
        // 其它节点按照原逻辑
        return super.getAttribute(name);
    }

    @Override
    public ServletInputStream getInputStream() {
        return new DecryptBodyServletInputStream(body);
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream(), StandardCharsets.UTF_8));
    }

    public String getBodyString() {
        return this.bodyString;
    }

}
